#!/usr/bin/env python
# -*- coding: utf-8 -*-


import os
import subprocess
import yaml
import time
from core.module_interfaces import TESTMODULE
from core.utils.tests import read_conf
from core.utils.log import logger


class Archive(TESTMODULE):
    def run(self, subflow):
        if subflow.config.subcommand != 'archive':
            return

        print("Archiving .... ")
        archive_dir = (
            'test_result_path',
        )
        try:
            if subflow.config.parser['name']:
                job_name = subflow.config.parser['name']
            else:
                job_name = ""
            if job_name:
                tarball = job_name + ".tar"
            else:
                if not subflow.config.parser['results']:
                    tarball = "test_tool.tar"
                else:
                    tarball = "test_result.tar"

            pack_only = subflow.config.parser["tar"]
            if not pack_only:
                tarball = tarball + ".gz"

            tarball = os.path.join(
                subflow.config.tone_path,
                tarball
            )
            self.remove_file(tarball)
            if subflow.config.parser['suite']:
                suite_list = subflow.config.parser['suite']
                archive_dir = []
                for sn in suite_list:
                    if not os.path.exists(os.path.join(subflow.config.test_result_path, sn)):
                        logger.warning("suite name {} is not found in result dir".format(sn))
            else:
                suite_list = []

            # prep job.yaml
            all_test_conf = self.get_all_test_conf(subflow.config.test_conf_path)
            job_file = os.path.join(subflow.config.tone_path, "job.yaml")
            job_yaml = self.get_job_yaml(test_result_path=subflow.config.test_result_path, all_test_conf=all_test_conf, name=job_name, suite_list=suite_list)
            self.write_to_yaml(job_yaml, job_file=job_file)

            target_dirs = []
            if not subflow.config.parser['results']:
                for d in subflow.config.frame_tool:
                    target = os.path.join(
                        subflow.config.tone_path, d)
                    print(target)
                    target_dirs.append(target)
            for d in archive_dir:
                print(subflow.config[d])
                target_dirs.append(subflow.config[d])
            for d in suite_list:
                suite_dir = os.path.join(subflow.config['test_result_path'], d)
                target_dirs.append(suite_dir)
            target_dirs = [i for i in target_dirs if os.path.exists(i)]
            target_dirs.append(job_file)
            self.create_tar(tarball, subflow.config.tone_path, target_dirs, pack_only=pack_only)
            print(
                "Done\n"
                "Archive file: {}".format(tarball)
            )
        except Exception as e:
            self.remove_file(tarball)
            raise e

    def remove_file(self, filename):
        if os.path.exists(filename) and os.path.isfile(filename):
            os.remove(filename)
        elif os.path.exists(filename):
            raise Exception("The same target {} exists".format(filename))

    # def create_tar(self, tarball, src):
    #     os.chdir(os.path.dirname(src))
    #     cmd = ["/bin/zip"]
    #     if os.path.exists(tarball):
    #         cmd.append("-urq")
    #     else:
    #         cmd.append("-rq")
    #     cmd.append(tarball)
    #     cmd.append(os.path.basename(src))
    #     ignore_path = os.path.join(
    #         os.path.basename(src),
    #         '.git'
    #     )
    #     if os.path.exists(ignore_path):
    #         cmd.append('-x')
    #         cmd.append(os.path.join(ignore_path, '*'))
    #     logger.debug(" ".join(cmd))
    #     subprocess.check_call(cmd)

    def create_tar(self, tarball, root_dir, src_dirs, pack_only=False):
        if not src_dirs or not root_dir:
            logger.debug("Create tarball skipped")
            return False
        root_dir = root_dir + "/"
        os.chdir(root_dir)
        if not pack_only:
            cmd = ["/bin/tar", "-zcvf", tarball]
        else:
            cmd = ["/bin/tar", "-cf", tarball]
        for src in src_dirs:
            cmd.append(src.replace(root_dir, ''))
        logger.debug(" ".join(cmd))
        subprocess.check_call(cmd)

    def is_result_exist(self, test_result_path, test_conf, suite_list=[]):
        suite, conf = test_conf.split(":")
        if len(suite_list) != 0 and suite not in suite_list:
            return False
        if "=" not in conf:
            _result_path = conf
        else:
            _result_path = "-".join([x.split("=")[1] for x in conf.split(",")])
        _path = os.path.join(suite, _result_path)
        return os.path.exists(os.path.join(test_result_path, _path))

    def get_job_yaml(self, test_result_path, all_test_conf, name="", suite_list=[]):
        if not name:
            name = self.gen_job_name()
        job = {"name": name, "test_config": []}
        ip = self.get_eth0_ip()
        os_info = self.get_os_info()
        gcc_info = self.get_gcc_info()
        glibc_info = self.get_glibc_info()
        kernel_info = self.get_kernel_info()
        disk_info = self.get_disk_info()
        cpu_info = self.get_cpu_info()
        mem_info = self.get_mem_info()
        net_info = self.get_network_info()
        bios_info = self.get_bios_info()
        arch_info = self.get_arch_info()
        test_suites = {}
        for test_conf in all_test_conf:
            if self.is_result_exist(test_result_path, test_conf, suite_list):
                suite, conf = test_conf.split(":")
                if suite not in test_suites:
                    test_suites[suite] = [conf]
                else:
                    test_suites[suite].append(conf)

        for suite in test_suites:
            test_suite = {"test_suite": suite, "cases": []}
            for case in test_suites[suite]:
                test_case = {
                                "test_case": case, 
                                "server": 
                                    {
                                        "ip": ip,
                                        "distro": os_info,
                                        "kernel_version": kernel_info,
                                        "glibc": glibc_info,
                                        "gcc": gcc_info,
                                        "disk": disk_info,
                                        "cpu_info": cpu_info,
                                        "memory_info": mem_info,
                                        "ether": net_info,
                                        "bios": bios_info,
                                        "arch":arch_info
                                    }
                            }
                test_suite["cases"].append(test_case)
            job["test_config"].append(test_suite)
        return job

    def write_to_yaml(self, job, job_file):
        with open(job_file, "w") as f:
            f.write(yaml.dump(job))

    def get_eth0_ip(self):
        try:
            res = os.popen("ifconfig | grep inet | awk -F ' ' '{print $2}' | head -1").read()
            return res
        except:
            return "127.0.0.1"

    def get_os_info(self):
        try:
            os_name = os.popen("cat /etc/os-release | grep ^ID= | awk -F= '{print $2}' | sed 's|\"||g'").read().strip()
            os_ver = os.popen("cat /etc/os-release | grep ^VERSION_ID= | awk -F= '{print $2}' | sed 's|\"||g'").read().strip()
            return os_name + os_ver
        except:
            return None

    def get_gcc_info(self):
        try:
            gcc_info = os.popen("gcc --version").read().strip()
            return gcc_info
        except:
            return None

    def get_glibc_info(self):
        try:
            glibc_info = os.popen("ldd --version").read().strip()
            return glibc_info
        except:
            return None

    def get_kernel_info(self):
        try:
            kernel_info = os.popen("uname -r").read().strip()
            return kernel_info
        except:
            return None

    def get_bios_info(self):
        try:
            bios_info = os.popen("dmidecode -t 0").read().strip()
            return bios_info
        except:
            return None

    def get_mem_info(self):
        try:
            mem_info = os.popen("cat /proc/meminfo").read().strip()
            return mem_info
        except:
            return None

    def get_cpu_info(self):
        try:
            cpu_info = os.popen("lscpu").read().strip()
            return cpu_info
        except:
            return None

    def get_disk_info(self):
        try:
            disk_info = os.popen("df -Th").read().strip()
            return disk_info
        except:
            return None

    def get_network_info(self):
        try:
            net_info = os.popen("ifconfig").read().strip()
            return net_info
        except:
            return None

    def get_arch_info(self):
        try:
            arch_info = os.popen("arch").read().strip()
            return arch_info
        except:
            return None

    def gen_job_name(self):
        return "offline_job_" + str(time.strftime("%Y%m%d_%H-%M-%S", time.localtime()))

    def get_all_test_conf(self, conf_path):
        test_conf = []
        if not os.path.exists(conf_path):
            raise Exception("Can NOT get test conf: {} not exist!".format(conf_path))
            return None
        posible_category = [
            'functional',
            'performance',
            'stress',
        ]
        for category in posible_category:
            curr_path = os.path.join(conf_path, category)
            if not os.path.exists(curr_path):
                continue
            configs = os.listdir(curr_path)
            for c in configs:
                if not c.endswith(".conf"):
                    continue
                suite = c.split(".")[0]
                conf_file = os.path.join(curr_path, c)
                value, indvalue, fields = read_conf(conf_file, suite=suite)
                for i in indvalue:
                    if "testconf" in i:
                        test_conf.append(i["testconf"])
        return test_conf
